package com.tanhua.server.service;

import com.alibaba.fastjson.JSONArray;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.*;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.ReportVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class TestSoulService {
    @DubboReference
    private MockApi mockApi;

    @DubboReference
    private MockQuestionApi mockQuestionApi;

    @DubboReference
    private OptionApi optionApi;

    @DubboReference
    private ReportApi reportApi;

    @DubboReference
    private UserConclusionApi userConclusionApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    /**
     * 查出问卷
     *
     * @return
     */
    public List<Mock> getMockList() {
        Long userId = UserHolder.getUserId();
        UserConclusion userConclusion = userConclusionApi.findUserLevelByUserId(userId);
        //当前用户的等级
        Integer userLevel = userConclusion == null ? 1 : userConclusion.getLevel();
        //先获得问卷列表
        // TODO: 2022/1/9 注意此处还要设置问卷问题个数为10个,问题的选项个数为7个
        List<Mock> mocks = mockApi.findMockList();//需要增加问题列表
        //封装信息
        mocks = mocks.stream().map(
                m -> {
                    //获取问题列表
                    List<MockQuestion> mockQuestions = mockQuestionApi.findMockQuestionListByMockId(m.getId());
                    m.setQuestions(mockQuestions);
                    //判断权限
                    // 判断其等级
                    String level = m.getLevel();
                    Integer mockLevel = "初级".equals(level) ? 1 : "中级".equals(level) ? 2 : 3;
                    //如果用户等级小于当前问卷等级则锁住相应试卷
                    if (userLevel.intValue() - mockLevel.intValue() < 0) {
                        m.setIsLock(1);
                    } else {
                        m.setIsLock(0);
                    }
                    return m;
                }
        ).collect(Collectors.toList());
        return mocks;
    }

    /**
     * 提交结果
     *
     * @param answers
     * @return
     */
    public String submit(List<Answer> answers) {
        //1.查询option表格,计算总分
        Integer totalScore = optionApi.sum(answers);
        //2.根据总分判断类型,并封装
        String conclusion;
        String cover;
        if (totalScore > 0 && totalScore <= 20) {
            //为狐狸
            conclusion = Constants.REPORT_CONCLUSION_FOX;
            cover = Constants.REPORT_COVER_FOX;
        } else if (totalScore > 20 && totalScore <= 40) {
            //为狮子
            conclusion = Constants.REPORT_CONCLUSION_LION;
            cover = Constants.REPORT_COVER_LION;
        } else if (totalScore > 40 && totalScore <= 60) {
            //为兔子
            conclusion = Constants.REPORT_CONCLUSION_RABBIT;
            cover = Constants.REPORT_COVER_RABBIT;
        } else {
            //猫头鹰
            conclusion = Constants.REPORT_CONCLUSION_OWL;
            cover = Constants.REPORT_COVER_OWL;
        }
        //3.根据问题查询问题信息
        Answer answer = answers.get(0);
        MockQuestion mockQuestion = mockQuestionApi.findQuestionById(answer.getQuestionId());
        if (mockQuestion == null) throw new BusinessException(ErrorResult.builder().errMessage("试题为空").build());
        String mockId = mockQuestion.getMockId();
        //4.根据id查问卷信息
        Mock mock = mockApi.findById(mockId);
        if (mock == null) throw new BusinessException(ErrorResult.builder().errMessage("问卷为空").build());
        //5.对象进行封装保存
        Report report = new Report();
        report.setConclusion(conclusion);
        report.setCover(cover);
        //自己生成的一个id
        String reportId = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        reportId += Math.random() * 10000;
        reportId = reportId.substring(0, 18);
        report.setId(reportId);
        Long userId = UserHolder.getUserId();
        report.setUserId(userId);
        report.setTotalScore(totalScore);
        String level = mock.getLevel();
        report.setMockLevel(level);
        // TODO: 2022/1/9 主要这里维度的关系怎么生成,此处是直接封装了一个,后期需添加相应的关系逻辑
        //要封装dimensionsStr
        report.mySetDimensionStr(80, 70, 60, 50);
        //6.保存报告信息
        // TODO: 2022/1/9 需要考虑的是同等级的报告是否要覆盖,现在还未考虑覆盖,只是新增
        reportApi.save(report);
        //7.保存后要更改下一级别的文件的权限
        /*if ("初级".equals(level)){
            //更改中级的权限
            mockApi.unLOCK("中级");
        }else if("中级".equals(level)){
            mockApi.unLOCK("高级");
        }*/
        //上面方法一改都改了
        Integer userLevel = "初级".equals(level) ? 2 : "中级".equals(level) || "高级".equals(level) ? 3 : 1;
        //8.更新或保存用户的属性
        UserInfo userInfo = userInfoApi.findById(userId);
        UserConclusion userConclusion = UserConclusion.init(userInfo);
        userConclusion.setConclusion(conclusion);
        userConclusion.setLevel(userLevel);
        userConclusionApi.updateOrSave(userConclusion);
        return reportId;
    }

    /**
     * 查看报告
     *
     * @param reportId
     * @return
     */
    public ReportVo getReport(String reportId) {
        //1.查询数据库表的数据,返回前要进行一个维度的转换文本转换成对象,懒得建表
        Report report = reportApi.getReportById(reportId);
        String dimensionsStr = report.getDimensionsStr();
        List<Dimension> dimensions = JSONArray.parseArray(dimensionsStr, Dimension.class);
        //2.同时前端需要相似人的数据,只要10个,自己定的鉴定结果一致则判定其为相似,需求中没明确
        // TODO: 2022/1/9 如果后期维度进行了相应的逻辑编写,则此处应该还要判断维度相似性
        String conclusion = report.getConclusion();
        List<UserConclusion> userConclusions = userConclusionApi.findTenUserConclusionByConclusion(conclusion);
        //封装信息
        ReportVo reportVo = new ReportVo();
        BeanUtils.copyProperties(report, reportVo);
        // TODO: 2022/1/9 找相似是否要排除自己 ,还未考虑排除自己
        reportVo.setSimilarYou(userConclusions);
        reportVo.setDimensions(dimensions);
        return reportVo;
    }
}
